//----------------------------------------------------------------------------
// M A R I T I M E  R E S E A R C H  I N S T I T U T E  N E T H E R L A N D S
//----------------------------------------------------------------------------
// Copyright (C) 2012 - MARIN - All rights reserved - http://www.marin.nl
//----------------------------------------------------------------------------
// Program    : mermaid
// Module     : vbm
// File       : CudaIncomingWaves.h
// Author     : M.A. de Jong
//----------------------------------------------------------------------------

#ifndef CUDAINCOMINGWAVES_H
#define CUDAINCOMINGWAVES_H

#include "defines.h"
#include "Array1D.h"
#include "Array2D.h"
#include "CUDAPACKAGE/common/globals.h"

//----------------------------------------------------------------------------
// class CudaIncomingWaves
//----------------------------------------------------------------------------
class CudaIncomingWaves
{

public:

    CudaIncomingWaves(const int Nx1,
                      const int Nx2,
                      const int wvin_spec_count);

    virtual ~CudaIncomingWaves();

    void initialize(const Array1D<int > *hwvin_N_count,
                    const Array2D<REAL> *hwvin_N_ext_ampl,
                    const Array2D<REAL> *hwvin_N_ext_phase,
                    const Array2D<REAL> *hwvin_N_ext_freq,
                    const Array2D<REAL> *hwvin_N_ext_facphi,
                    const Array2D<REAL> *hwvin_N_ext_facpsi,
                    const Array2D<REAL> *hwvin_N_cen_ampl,
                    const Array2D<REAL> *hwvin_N_cen_phase,
                    const Array2D<REAL> *hwvin_N_cen_freq,
                    const Array2D<REAL> *hwvin_N_cen_facphi,
                    const Array2D<REAL> *hwvin_N_cen_facpsi,
                    const Array2D<REAL> *hwvin_N_int_ampl,
                    const Array2D<REAL> *hwvin_N_int_phase,
                    const Array2D<REAL> *hwvin_N_int_freq,
                    const Array2D<REAL> *hwvin_N_int_facphi,
                    const Array2D<REAL> *hwvin_N_int_facpsi,
                    const Array1D<int > *hwvin_E_count,
                    const Array2D<REAL> *hwvin_E_ext_ampl,
                    const Array2D<REAL> *hwvin_E_ext_phase,
                    const Array2D<REAL> *hwvin_E_ext_freq,
                    const Array2D<REAL> *hwvin_E_ext_facphi,
                    const Array2D<REAL> *hwvin_E_ext_facpsi,
                    const Array2D<REAL> *hwvin_E_cen_ampl,
                    const Array2D<REAL> *hwvin_E_cen_phase,
                    const Array2D<REAL> *hwvin_E_cen_freq,
                    const Array2D<REAL> *hwvin_E_cen_facphi,
                    const Array2D<REAL> *hwvin_E_cen_facpsi,
                    const Array2D<REAL> *hwvin_E_int_ampl,
                    const Array2D<REAL> *hwvin_E_int_phase,
                    const Array2D<REAL> *hwvin_E_int_freq,
                    const Array2D<REAL> *hwvin_E_int_facphi,
                    const Array2D<REAL> *hwvin_E_int_facpsi,
                    const Array1D<int > *hwvin_S_count,
                    const Array2D<REAL> *hwvin_S_ext_ampl,
                    const Array2D<REAL> *hwvin_S_ext_phase,
                    const Array2D<REAL> *hwvin_S_ext_freq,
                    const Array2D<REAL> *hwvin_S_ext_facphi,
                    const Array2D<REAL> *hwvin_S_ext_facpsi,
                    const Array2D<REAL> *hwvin_S_cen_ampl,
                    const Array2D<REAL> *hwvin_S_cen_phase,
                    const Array2D<REAL> *hwvin_S_cen_freq,
                    const Array2D<REAL> *hwvin_S_cen_facphi,
                    const Array2D<REAL> *hwvin_S_cen_facpsi,
                    const Array2D<REAL> *hwvin_S_int_ampl,
                    const Array2D<REAL> *hwvin_S_int_phase,
                    const Array2D<REAL> *hwvin_S_int_freq,
                    const Array2D<REAL> *hwvin_S_int_facphi,
                    const Array2D<REAL> *hwvin_S_int_facpsi,
                    const Array1D<int > *hwvin_W_count,
                    const Array2D<REAL> *hwvin_W_ext_ampl,
                    const Array2D<REAL> *hwvin_W_ext_phase,
                    const Array2D<REAL> *hwvin_W_ext_freq,
                    const Array2D<REAL> *hwvin_W_ext_facphi,
                    const Array2D<REAL> *hwvin_W_ext_facpsi,
                    const Array2D<REAL> *hwvin_W_cen_ampl,
                    const Array2D<REAL> *hwvin_W_cen_phase,
                    const Array2D<REAL> *hwvin_W_cen_freq,
                    const Array2D<REAL> *hwvin_W_cen_facphi,
                    const Array2D<REAL> *hwvin_W_cen_facpsi,
                    const Array2D<REAL> *hwvin_W_int_ampl,
                    const Array2D<REAL> *hwvin_W_int_phase,
                    const Array2D<REAL> *hwvin_W_int_freq,
                    const Array2D<REAL> *hwvin_W_int_facphi,
                    const Array2D<REAL> *hwvin_W_int_facpsi);

    void wvin_comp(const REAL t, const REAL pslow,
                   Array1D<REAL> *hzeta_in_N_ext, 
                   Array1D<REAL> *hphi_in_N_ext, 
                   Array1D<REAL> *hpsi_in_N_ext,
                   Array1D<REAL> *hzeta_in_N_cen, 
                   Array1D<REAL> *hphi_in_N_cen, 
                   Array1D<REAL> *hpsi_in_N_cen,
                   Array1D<REAL> *hzeta_in_N_int, 
                   Array1D<REAL> *hphi_in_N_int, 
                   Array1D<REAL> *hpsi_in_N_int,
                   Array1D<REAL> *hzeta_in_E_ext, 
                   Array1D<REAL> *hphi_in_E_ext, 
                   Array1D<REAL> *hpsi_in_E_ext,
                   Array1D<REAL> *hzeta_in_E_cen, 
                   Array1D<REAL> *hphi_in_E_cen, 
                   Array1D<REAL> *hpsi_in_E_cen,
                   Array1D<REAL> *hzeta_in_E_int, 
                   Array1D<REAL> *hphi_in_E_int, 
                   Array1D<REAL> *hpsi_in_E_int,
                   Array1D<REAL> *hzeta_in_S_ext, 
                   Array1D<REAL> *hphi_in_S_ext, 
                   Array1D<REAL> *hpsi_in_S_ext,
                   Array1D<REAL> *hzeta_in_S_cen, 
                   Array1D<REAL> *hphi_in_S_cen, 
                   Array1D<REAL> *hpsi_in_S_cen,
                   Array1D<REAL> *hzeta_in_S_int, 
                   Array1D<REAL> *hphi_in_S_int, 
                   Array1D<REAL> *hpsi_in_S_int,
                   Array1D<REAL> *hzeta_in_W_ext, 
                   Array1D<REAL> *hphi_in_W_ext, 
                   Array1D<REAL> *hpsi_in_W_ext,
                   Array1D<REAL> *hzeta_in_W_cen, 
                   Array1D<REAL> *hphi_in_W_cen, 
                   Array1D<REAL> *hpsi_in_W_cen,
                   Array1D<REAL> *hzeta_in_W_int, 
                   Array1D<REAL> *hphi_in_W_int, 
                   Array1D<REAL> *hpsi_in_W_int);

private:

    /// @cond nevercall
    CudaIncomingWaves();
    CudaIncomingWaves(const CudaIncomingWaves& m);
    CudaIncomingWaves & operator =(const CudaIncomingWaves& m);
    /// @endcond

    void setup();

    void cleanup();

    void determineSizes();

    int maxNoWaves(const Array1D<int> *array);

    const int m_Nx1;
    const int m_Nx2;
    const int m_wvin_spec_count;

    int m_Nc;
    int m_Nr;

    // North
    int  *m_dwvin_N_count;
    REAL *m_dwvin_N_ext_ampl;
    REAL *m_dwvin_N_cen_ampl;
    REAL *m_dwvin_N_int_ampl;
    REAL *m_dwvin_N_ext_phase;
    REAL *m_dwvin_N_cen_phase;
    REAL *m_dwvin_N_int_phase;
    REAL *m_dwvin_N_ext_freq;
    REAL *m_dwvin_N_cen_freq;
    REAL *m_dwvin_N_int_freq;
    REAL *m_dwvin_N_ext_facphi;
    REAL *m_dwvin_N_cen_facphi;
    REAL *m_dwvin_N_int_facphi;
    REAL *m_dwvin_N_ext_facpsi;
    REAL *m_dwvin_N_cen_facpsi;
    REAL *m_dwvin_N_int_facpsi;

    // East
    int  *m_dwvin_E_count;
    REAL *m_dwvin_E_ext_ampl;
    REAL *m_dwvin_E_cen_ampl;
    REAL *m_dwvin_E_int_ampl;
    REAL *m_dwvin_E_ext_phase;
    REAL *m_dwvin_E_cen_phase;
    REAL *m_dwvin_E_int_phase;
    REAL *m_dwvin_E_ext_freq;
    REAL *m_dwvin_E_cen_freq;
    REAL *m_dwvin_E_int_freq;
    REAL *m_dwvin_E_ext_facphi;
    REAL *m_dwvin_E_cen_facphi;
    REAL *m_dwvin_E_int_facphi;
    REAL *m_dwvin_E_ext_facpsi;
    REAL *m_dwvin_E_cen_facpsi;
    REAL *m_dwvin_E_int_facpsi;

    // South
    int  *m_dwvin_S_count;
    REAL *m_dwvin_S_ext_ampl;
    REAL *m_dwvin_S_cen_ampl;
    REAL *m_dwvin_S_int_ampl;
    REAL *m_dwvin_S_ext_phase;
    REAL *m_dwvin_S_cen_phase;
    REAL *m_dwvin_S_int_phase;
    REAL *m_dwvin_S_ext_freq;
    REAL *m_dwvin_S_cen_freq;
    REAL *m_dwvin_S_int_freq;
    REAL *m_dwvin_S_ext_facphi;
    REAL *m_dwvin_S_cen_facphi;
    REAL *m_dwvin_S_int_facphi;
    REAL *m_dwvin_S_ext_facpsi;
    REAL *m_dwvin_S_cen_facpsi;
    REAL *m_dwvin_S_int_facpsi;

    // West
    int  *m_dwvin_W_count;
    REAL *m_dwvin_W_ext_ampl;
    REAL *m_dwvin_W_cen_ampl;
    REAL *m_dwvin_W_int_ampl;
    REAL *m_dwvin_W_ext_phase;
    REAL *m_dwvin_W_cen_phase;
    REAL *m_dwvin_W_int_phase;
    REAL *m_dwvin_W_ext_freq;
    REAL *m_dwvin_W_cen_freq;
    REAL *m_dwvin_W_int_freq;
    REAL *m_dwvin_W_ext_facphi;
    REAL *m_dwvin_W_cen_facphi;
    REAL *m_dwvin_W_int_facphi;
    REAL *m_dwvin_W_ext_facpsi;
    REAL *m_dwvin_W_cen_facpsi;
    REAL *m_dwvin_W_int_facpsi;

    // North
    REAL *m_dzeta_in_N_int;
    REAL *m_dphi_in_N_int;
    REAL *m_dpsi_in_N_int;

    // East
    REAL *m_dzeta_in_E_int;
    REAL *m_dphi_in_E_int;
    REAL *m_dpsi_in_E_int;

    // South
    REAL *m_dzeta_in_S_int;
    REAL *m_dphi_in_S_int;
    REAL *m_dpsi_in_S_int;

    // West
    REAL *m_dzeta_in_W_int;
    REAL *m_dphi_in_W_int;
    REAL *m_dpsi_in_W_int;


    // Note: The same vectors are used by CudaWavesComputer!
    //       In the current version the next data is copied 
    //       H2D and D2H

    // North
    REAL *m_dzeta_in_N_ext;
    REAL *m_dphi_in_N_ext;
    REAL *m_dpsi_in_N_ext;
    REAL *m_dzeta_in_N_cen;
    REAL *m_dphi_in_N_cen;
    REAL *m_dpsi_in_N_cen;

    // East
    REAL *m_dzeta_in_E_ext;
    REAL *m_dphi_in_E_ext;
    REAL *m_dpsi_in_E_ext;
    REAL *m_dzeta_in_E_cen;
    REAL *m_dphi_in_E_cen;
    REAL *m_dpsi_in_E_cen;

    // South
    REAL *m_dzeta_in_S_ext;
    REAL *m_dphi_in_S_ext;
    REAL *m_dpsi_in_S_ext;
    REAL *m_dzeta_in_S_cen;
    REAL *m_dphi_in_S_cen;
    REAL *m_dpsi_in_S_cen;

    // West
    REAL *m_dzeta_in_W_ext;
    REAL *m_dphi_in_W_ext;
    REAL *m_dpsi_in_W_ext;
    REAL *m_dzeta_in_W_cen;
    REAL *m_dphi_in_W_cen;
    REAL *m_dpsi_in_W_cen;


    int m_maxN;
    int m_maxE;
    int m_maxS;
    int m_maxW;

    // streams
    cudaStream_t m_stream1;
    cudaStream_t m_stream2;
    cudaStream_t m_stream3;
    cudaStream_t m_stream4;
    cudaStream_t m_stream5;
    cudaStream_t m_stream6;
    cudaStream_t m_stream7;
    cudaStream_t m_stream8;
    cudaStream_t m_stream9;
    cudaStream_t m_stream10;
    cudaStream_t m_stream11;
    cudaStream_t m_stream12;

};

#endif // CUDAINCOMINGWAVES_H
